﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CMA_ES
{
    class Matrix2D
    {
        int[,] _matrix;
        int _width;
        int _height;

        public int this[int a, int b]
        {
            get { return _matrix[a, b]; }
            set { _matrix[a, b] = value; }
        }

        public int Width { get { return _width; } }
        public int Height { get { return _height; } }

        public Matrix2D(int width, int height)
        {
            if (width < 1 || height < 1)
                throw new ArgumentException("Matrix size must have positive value");
            _matrix = new int[width, height];
            _width = width;
            _height = height;
        }

        public Matrix2D(int size)
        {
            if (size < 1)
                throw new ArgumentException("Matrix size must have positive value");
            _matrix = new int[size, size];
            _width = size;
            _height = size;
        }

        public static Matrix2D operator *(Matrix2D A, Matrix2D B)
        {
            if (A.Width != B.Height)
                throw new ArgumentException("A.Width and B.Height must have the same value");

            Matrix2D C = new Matrix2D(B.Width, A.Height);
            for (int i = 0; i < A.Height; i++)
            {
                for (int j = 0; j < B.Width; j++)
                {
                    for (int x = 0; x < A.Width; x++)
                    {
                        C[j, i] += A[x, i] * B[j, x];
                    }
                }
            }
            return C;
        }

        public static Matrix2D operator +(Matrix2D A, Matrix2D B)
        {
            if (A.Width != B.Width && A.Height != B.Height)
                throw new ArgumentException("The matrices must be of equal sizes");

            Matrix2D C = new Matrix2D(A.Width, A.Height);
            for (int i = 0; i < A.Width; i++)
            {
                for (int j = 0; j < A.Height; j++)
                {
                    C[i, j] = A[i, j] + B[i, j];
                }
            }

            return C;
        }

        public static Matrix2D operator -(Matrix2D A, Matrix2D B)
        {
            if (A.Width != B.Width && A.Height != B.Height)
                throw new ArgumentException("The matrices must be of equal sizes");

            Matrix2D C = new Matrix2D(A.Width, A.Height);
            for (int i = 0; i < A.Width; i++)
            {
                for (int j = 0; j < A.Height; j++)
                {
                    C[i, j] = A[i, j] - B[i, j];
                }
            }
            return C;
        }

        public static Matrix2D Ones(int width,int height)
        {
            Matrix2D result = new Matrix2D(width, height);
            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    result[i, j] = 1;
                }
            }
            return result;
        }

        public static Matrix2D Eye(int size)
        {
            Matrix2D result = new Matrix2D(size);
            for (int i = 0; i < size; i++)
            {
                result[i, i] = 1;
            }
            return result;
        }

        public static Matrix2D Diag(Matrix2D matrix)
        {
            if (matrix.Width != matrix.Height)
                throw new ArgumentException("Matrix must be of equal sizes");

            Matrix2D result = new Matrix2D(matrix.Width, matrix.Height);
            for (int i = 0; i < matrix.Width; i++)
            {
                result[i, i] = matrix[i, i];
            }
            return result;
        }

        public void MatrixToConsole()
        {
            for (int i = 0; i < this.Width; i++)
            {
                for (int j = 0; j < this.Height; j++)
                {
                    Console.Write(this[i, j] + "\t");
                }
                Console.WriteLine();
            }
        }
    }
}
